diff -ur vtun-3.0.1/linux/tun_dev.c vtun-3.0.1-ipv6/linux/tun_dev.c
--- vtun-3.0.1/linux/tun_dev.c	2006-12-11 19:45:35.000000000 +0900
+++ vtun-3.0.1-ipv6/linux/tun_dev.c	2009-10-19 10:09:03.000000000 +0900
@@ -32,11 +32,19 @@
 
 #include <sys/ioctl.h>
 #include <sys/socket.h>
+#include <netinet/ip.h>
 #include <linux/if.h>
+#include <linux/if_ether.h>
 
 #include "vtun.h"
 #include "lib.h"
 
+#if defined(ETH_P_IPV6) && defined(ETH_P_IP)
+#define LINUX_TUN_IPV6 1
+#else
+#define LINUX_TUN_IPV6 0
+#endif
+
 /* 
  * Allocate TUN device, returns opened fd. 
  * Stores dev name in the first arg(must be large enough).
@@ -92,6 +100,15 @@
 
     memset(&ifr, 0, sizeof(ifr));
     ifr.ifr_flags = (istun ? IFF_TUN : IFF_TAP) | IFF_NO_PI;
+#if LINUX_TUN_IPV6
+    /*
+     * the OS expects us to do something special to the tun
+     * socket in order to support IPv6, i.e. it is not transparent
+     * via tun device.
+     */
+    if (istun)
+       ifr.ifr_flags &= ~IFF_NO_PI;
+#endif
     if (*dev)
        strncpy(ifr.ifr_name, dev, IFNAMSIZ);
 
@@ -125,8 +142,52 @@
 int tap_close(int fd, char *dev) { return close(fd); }
 
 /* Read/write frames from TUN device */
-int tun_write(int fd, char *buf, int len) { return write(fd, buf, len); }
+int tun_write(int fd, char *buf, int len) {
+#if LINUX_TUN_IPV6
+    struct tun_pi pi;
+    struct iphdr *iph;
+    struct iovec vect[2];
+    int ret;
+
+    iph = (struct iphdr *)buf;
+
+    pi.flags = 0;
+
+    if(iph->version == 6)
+       pi.proto = htons(ETH_P_IPV6);
+    else
+       pi.proto = htons(ETH_P_IP);
+
+    vect[0].iov_len = sizeof(pi);
+    vect[0].iov_base = &pi;
+    vect[1].iov_len = len;
+    vect[1].iov_base = buf;
+
+    ret = writev(fd, vect, 2);
+    return(ret - sizeof(pi));
+#else
+    return write(fd, buf, len);
+#endif
+}
+
 int tap_write(int fd, char *buf, int len) { return write(fd, buf, len); }
 
-int tun_read(int fd, char *buf, int len) { return read(fd, buf, len); }
+int tun_read(int fd, char *buf, int len) {
+#if LINUX_TUN_IPV6
+    struct iovec vect[2];
+    struct tun_pi pi;
+    int ret;
+
+    vect[0].iov_len = sizeof(pi);
+    vect[0].iov_base = &pi;
+    vect[1].iov_len = len;
+    vect[1].iov_base = buf;
+
+    ret = readv(fd, vect, 2);
+    return(ret - sizeof(pi));
+#else
+    return read(fd, buf, len);
+#endif
+}
+
 int tap_read(int fd, char *buf, int len) { return read(fd, buf, len); }
