Re: Kernel tunnel driver and routing?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi!

On 16:56 Fri 05 Mar     , Robin Gilks wrote:
> > Hi!
> >
> > On 11:42 Thu 04 Mar     , Robin Gilks wrote:
> >> Greetings
> >>
> >> I put a question mark at the end of the subject line because I'm not
> >> sure
> >> if the problem I have is to do with routing or not... First of all,
> >> define
> >> the problem.
> >>
> >> I'm using the tun driver within an application that opens a tunnel and
> >> reads encapsulated data from the tunnel, munges it about (as
> >> applications
> >> do!!) and then sends the reply back down the tunnel.
> >>
> >> So far, I can open the tunnel and read data but the send data seems to
> >> just disappear. Looking at ifconfig I see the send packet count and the
> >> send byte counts increment but nothing traced on my wireshark monitor:-(
> >
> > This sounds interesting. If you do not mind, I would like to see to source
> > code.
> >
> 
> OK - here is the code snippet that half works - the '#if 0' around the
> 'set_addresses()' function is due to work in progress (i.e. not very
> much!!).
> 
> The remote system is set up to push all of 10.0.0.0/8 down the tunnel to
> the target but I've tried to make the code address agnostic :-)

You strip off the ip header and than you change some data fields which are not
the ip address anymore...

...

> struct message
> {
>    int length;                  /* number of characters in packet  */
>    unsigned char msg[MAX_SIZE]; /* the packet itself               */
> };

...

> /*
>  * Read data from the specified interface. Return a complete IP datagram.
>  * If the packet is not complete, then don't return anything.
>  * By experiment the packet returned has the ethernet and outer IP header attached still so skip them (32 bytes)
>  */
> int
> tun_read (int fd, struct message *m)
> {
>    int n;
>    char buf[MAX_SIZE];
> 
>    n = read (fd, (char *) buf, MAX_SIZE);
>    if (n < 0)
>    {
>       m->length = 0;
>       if (errno == EINTR)
>          return 0;
>       if (errno == EWOULDBLOCK)
>          return 0;
>       printf ("read from tunnel device");
>       return -1;
>    }
>    memcpy ((char *) m->msg, buf + 32, n - 32);
>    m->length = n - 32;
>    return n - 32;

You strip off the header here.

> }
> 
> /*
>  * write data to the specified interface. Return as soon as possible.
>  * The buffer provided will be a complete IP datagram.
>  */
> int
> tun_send (int fd, struct message *m)
> {
>    int n;
>    char buf[MAX_SIZE];
> 
> 
>    if (m->length <= 0)
>       return 0;
> 
>    memset (buf, 0, 32);
>    memcpy (buf + 32, (char *) m->msg, m->length);
>    n = write (fd, buf, m->length + 32);

Here, you create a header with all 0...

>    if (n < 0)
>    {
>       if (errno == EINTR)
>       {
>          printf ("Send: eintr\n");
>          return 0;
>       }
>       if (errno == EWOULDBLOCK)
>       {
>          printf ("Send: wouldblock\n");
>          return 0;
>       }
>       printf ("write to tunnel device");
>       return -1;
>    }
>    return n;
> }
> 
> 
> int
> main (int argc, char *argv[])
> {
>    int tun_fd, nread, i;
>    struct message m;
>    unsigned int srcip, dstip;
>    char name[10] = "tun%d";

...

>    /* Now read data coming from the kernel */
>    while (1)
>    {
>       /* Note that "buffer" should be at least the MTU size of the interface, eg 1500 bytes */
>       sleep (1);
>       nread = tun_read (tun_fd, &m);
>       if (nread < 0)
>       {
>          if (errno == EINTR)
>             continue;
>          if (errno == EWOULDBLOCK)
>          {
>             printf ("Reading\n");
>             continue;
>          }
>          perror ("Reading from interface");
>          close (tun_fd);
>          exit (1);
>       }
> 
>       if (nread > 0)
>       {
>          printf ("\nRead %d bytes from %d.%d.%d.%d to %d.%d.%d.%d\n", nread, m.msg[12], m.msg[13], m.msg[14], m.msg[15],
>                  m.msg[16], m.msg[17], m.msg[18], m.msg[19]);
>          for (i = 0; i < nread; i++)
>          {
>             if ((i & 15) == 0)
>                printf ("\n");
>             printf (" %02x", m.msg[i]);
>          }
>          printf ("\n");
> 
>          // swap source and destination IP addresses and send the packet back
>          (void) memcpy ((char *) &srcip, (char *) m.msg + 12, 4);
>          (void) memcpy ((char *) &dstip, (char *) m.msg + 16, 4);
>          (void) memcpy ((char *) m.msg + 16, (char *) &srcip, 4);
>          (void) memcpy ((char *) m.msg + 12, (char *) &dstip, 4);

Here you try to mangle the IP addresses, but actually this is the data you
mangle.

> 
>          tun_send (tun_fd, &m);
>       }
>    }
>    exit (0);
> }

I have attached a changed version of tuntest1.c which seems to run on my pc.
Take in mind that there is a 4 byte tuntap header before each packet, so the
offsets of the ip addresses are wrong by 4 byte.
Documentation/networking/tuntap.txt says these header are:
Flags [2 bytes]
Proto [2 bytes]

The tun_read might be a it broken, too. I do not think that you can issue a
read and expect that you always get one full packet back. If the packet is
bigger than the buffer, the packet might be split. If more than one packet
arrives at the same time, you might get more than one packet with a single
read. You could use the length value in the ip header to find out the real
length. However doing this might get you into trouble, if non IP arrives on
the tap device...

	-Michi
-- 
programing a layer 3+4 network protocol for mesh networks
see http://michaelblizek.twilightparadox.com


--
To unsubscribe from this list: send an email with
"unsubscribe kernelnewbies" to ecartis@xxxxxxxxxxxx
Please read the FAQ at http://kernelnewbies.org/FAQ


[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux