There isn't an option to remove the AF_INET attachment on tun packets
on OpenBSD at least, although there are ioctl's to add more "junk" at
the beginning, such as the sender ip address.

After checking the Linux kernel source, there seems to be an
option that MIGHT add info to packets, called "IFF_NO_PI",
which you set, meaning that you remove the PI-option and
don't add info to packets.

Now, I don't know what this PI stuff is for, the comments around it
are sparse, to say the least. ;-)

Here is a snippet from your code, on the 2.4 dynamic tun-stuff:

int
open_tun (const char *dev, char *actual, int size)
{
  <..cut some lines away...>
  ifr.ifr_flags = IFF_NO_PI;


And the corresponding Linux kernel code that gets to run
if IFF_NO_PI is not set (the flag name is TUN_NO_PI):

/* Get packet from user space buffer(already verified) */
static __inline__ ssize_t tun_get_user(struct tun_struct *tun, const
char *buf, size_t count)
{
        struct tun_pi pi = { 0, __constant_htons(ETH_P_IP) };
        register const char *ptr = buf; 
        register int len = count;
        struct sk_buff *skb;

        if (!(tun->flags & TUN_NO_PI)) {
                if ((len -= sizeof(pi)) < 0)
                        return -EINVAL;

                copy_from_user(&pi, ptr, sizeof(pi));
                ptr += sizeof(pi);
        }


This seems (to me) to mean:
if TUN_NO_PI is not set, and len gets sizeof(pi) subtracted but still
is larger (or eq) than 0, get a "pi" struct from userspace and copy
it to the beginning of the space that "ptr" is pointing to.

In the receive function, we see:

        struct tun_pi pi = { 0, skb->protocol };
        int len = count, total = 0;
        char *ptr = buf;

        if (!(tun->flags & TUN_NO_PI)) {
                if ((len -= sizeof(pi)) < 0)
                        return -EINVAL;

                if (len < skb->len) {
                        /* Packet will be striped */
                        pi.flags |= TUN_PKT_STRIP;
                }
 
                copy_to_user(ptr, &pi, sizeof(pi));

                total += sizeof(pi);
                ptr += sizeof(pi);
        }

Which seems to indicate that the protocol might be stored in the
tun_pi struct after all.
The tun_pi is defined to contain two unsigned shorts, one "flags" and
one "proto".
The TUN_PKT_STRIP seems to have no other effect than to just exist
so that someone might read it in the packet. But that's just my guess.

Next problem. The proto filled in by TUN is "htons(ETH_P_IP)" which
is 0x0800 in intel byte order, which would be something like
0x0008 if my htons guess is correct for a short.

So BSD and Linux say different things. BSDs say "here comes IPv4 stuff"
with AF_INET in a htonl(u_int_32) and Linux says
"here comes Ethernet IPv4 stuff" with two shorts, one containing
ETH_P_IP in intel byte order or it says nothing at all.

I think the solution would be to have openvpn disable TUN_NO_IP for
Linux tun devices and just not care about the actual value when
the packets arrive.

-- 
Janne Johansson
jan.johans...@biomatsys.com
BioMat Systems AB
Klarabergsg 37 3tr
111 21 Stockholm

Attachment: signature.asc
Description: This is a digitally signed message part

Reply via email to